﻿#define  _CRT_SECURE_NO_WARNINGS

/////////////////////////////////  继承部分内容理解  /////////////////////////////////

#include <iostream>
#include <string>
#include <vector>
#include <list>
#include <queue>

using namespace std;

///////////////// 继承的概念
// 参考讲义

// 当没有继承时 , 这时写以下代码
// 写一个简易版的学校认证系统

#if 0
class Student
{
	public :
	//身份认证
	void identity()
	{
		// ...
	} 
		// 学习
	void study()
	{
		// ...
	}
protected:
	string _name = "peter"; // 姓名
	string _address; // 地址
	string _tel; // 电话
	int _age = 18; // 年龄
	int _stuid; // 学号
};
class Teacher
{
	public :
	
	//身份认证
	void identity()
	{
		// ...
	} 
		// 授课
	void teaching()
	{
		//...
	}
protected:
	string _name = "张三"; // 姓名
	int _age = 18; // 年龄
	string _address; // 地址
	string _tel; // 电话
	string _title; // 职称
};


int main()
{
	return 0;
}

#endif

///////////// 用以上例子来了解继承的概念 

// 通过以上例子可以看出在 Student 和 Teacher 这两个类中都有相似的地方,并且不是一个           //
// 可以发现都有 :  姓名 \ 年龄 \ 地址 \ 电话 \ 职称 \ identity() 这些相同的地方            //
//            但 Student 有自己独特的地方 ------ study()                               //
//               Teacher 有自己独特的地方 ------ teaching()                           //
//  这个就正好符号继承的概念 , 我们可以在原有的一个类的基础上定义其它的函数接口等 , 产生派生类  //

///////////// 对于以上两个类不用继承会显得代码有点冗余了 , 这里就好比我们实现函数时 ,对同一方法多次调用时就可以实现一个函数单独封装
///////////// 这里也类似 


/////////////// 用继承的方式实现两个类

// 1. 继承定义的方式
// class Student  : public  Person 
//         |          |       |
//     派生类(子类)  继承方式  父类(基类)



/////////// 2 . 父类 

//父类 --- 包括两种类中相同的部分  ---- 父类的定义和普通类一样

////////// 这里就要补充 protected 和 private 的关系了

// 1. 父类中用 private ---- 派生类 和 父类外面 -- 都不能访问父类的私有成员 
#if 0 
class A
{
	public:
		A(int a = 0)
			:_a(a)
		{
			cout << "Person(int a = 0)" << endl;
			cout << "在本类中可以访问私有,保护,公有成员 :";

			cout <<"_a = " << _a << endl;
		}

// 私有派生类和类外面都不可见
	private:
		int _a;
};

// B 继承 A类

class B : public A
{

public:
	B(int a1 = 0)
		:_a1(a1)
	{
		cout << "B(int a1 = 0)" << endl;
		cout << "以公有方式继承父类 , 但父类中的成员是私有,B类中不能访问";

		// 定义会报错 :  error C2248: “A::_a”: 无法访问 private 成员(在“A”类中声明)
		//cout << "_a = " << _a << endl;
	}

private:
	int _a1;
};

#endif
// 2. 父类中用 protected ---- 派生类里可以访问父类的 protected成员 , 但类外面不可访问


#if 0
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "Person(int a = 0)" << endl;
		cout << "在本类中可以访问私有,保护,公有成员 :";

		cout << "_a = " << _a << endl;
	}

	// 私有派生类中可见 , 但类外面都不可见
protected:
	int _a;
};

// B 继承 A类

class B : public A
{

public:
	B(int a1 = 0)
		:_a1(a1)
	{
		cout << "B(int a1 = 0)" << endl;
		cout << "以公有方式继承父类 , 但父类中的成员是 protected,B类中可以访问 protected 成员";

		// ok 
		cout << "_a = " << _a << endl;
	}

private:
	int _a1;
};


int main()
{


	return 0;
}

#endif 


#if 0

//父类 
class Person
{
public:

	//身份认证
	void identity()
	{
		// ...
	}


//派生类可见 , 类外不可见
protected:
	// 相同部分
	string _name = "张三"; // 姓名
	string _address; // 地址
	string _tel; // 电话
	int _age = 18; // 年龄
};


// 派生类 Student
class Student : public Person
{
public:

	
	//Student 独有
	// 学习
	void study()
	{
		// ...
	}

private:
	//Student 独有
	int _stuid; // 学号
};


// 派生类 Teacher
class Teacher : public Person
{

public:

	//Teacher 独有
	// 授课
	void teaching()
	{
		//...
	}

private:
	//Teacher 独有
	string title; // 职称
};

int main()
{


	return 0;
}
#endif


////////// 继承方式的演示

//class Person
//{
//public :
//	Person(string name = "张三", int age = 20, string ip = "上海")
//		:_name(name)
//		, _age(age)
//		, _ip(ip)
//	{
//		
//	}
//	
//	void Print()
//	{
//		cout << _name << endl;
//	}
//
//public:
//	string _ip; // 地址
//protected:
//	string _name; // 姓名
//private:
//	int _age; // 年龄
//};
////class Student : protected Person
////class Student : private Person
//class Student : protected Person
//{
//public:
//	Student(int _stunum = 214)
//		:_stunum(_stunum)
//	{
//		// 基类的 private 在派生类中均不可访问
//		//cout << _age << endl;// err
//
//		// public 和 public继承 --- 可以访问 public
//		// protected 和 public继承 --- 可以访问 protected
//
//		//访问 public 成员
//		cout << _ip << endl;
//		//访问 protected 成员
//		cout << _name << endl;
//
//	}
//protected:
//	int _stunum; // 学号
//};
//
//
//int main()
//{
//	Student s;
//	Person p;
//
//
//	//cout << p._name << endl;
//	return 0;
//}


///////////////////////// 继承类模版

// 实现 stack


//依靠容器适配器实现
//template <class T , class Container = deque<T>>
//class Stack
//{
//public:
//
//
//private:
//
//};




// 依靠继承方式实现
// 继承 vector 

//namespace GJG
//{
//
//	template <class T>
//	class stack : public std::vector<T>
//	{
//	public:
//
//
//	private:
//
//	};
//}



/////// 在继承类模版后使用时 , 必须指定类域 .否则会报错 , 因为模版在调用对应函数时才会实例化

// 模版实例化

//	template<class T>
//	class A
//	{
//	public:
//		A()
//		{
//			//func();
//		}
//
//		void push(const T& x)
//		{
//			x.func();
//		}
//	};
//
//
//int main()
//{
//	A<int> aa;
//
//	//当没有调用该接口时就不会报错 , 因为没有模版实例化该接口
//	//aa.push(1);
//
//	//当调用时就会报错 :“.func”的左边必须有类/结构/联合
//	//aa.push(1);
//
//	return 0;
//}



////////// 当基类是类模版时 , 使用需要指定类域才可以

//用继承方式模拟实现 stack 

#if 0
namespace GJG
{

	template <class T>
	class stack : public std::vector<T>
	{
	public:

		void push(const T& data)
		{
			//需指定类域
			vector<T>::push_back(data);
		}

		void pop()
		{
			vector<T>::pop();

		}


		T& top()
		{

			return vector<T>::back();
		}


		bool empty()
		{
			return vector<T>::empty();
		}
	};
}


int main()
{
	GJG::stack<int> st;

	//若调用 push 时,没有指定类域使用,就会报错 : error C3861: “push_back”: 找不到标识符
	st.push(1);

	return 0;
}
#endif


//当还是继承方式实现时 , 可以写成宏的形式
#if 0
#define CONTAINER vector
namespace GJG
{

	template <class T>
	class stack : public std::CONTAINER<T>
	{
	public:

		void push(const T& data)
		{
			//需指定类域
			CONTAINER<T>::push_back(data);
		}

		void pop()
		{
			CONTAINER<T>::pop();

		}


		T& top()
		{

			return CONTAINER<T>::back();
		}


		bool empty()
		{
			return CONTAINER<T>::empty();
		}
	};
}

int main()
{

	GJG::stack<int> st;
	st.push(1);

	return 0;
}

#endif 


///// 基类在派生类的位置
#if 0
// 基类
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "Person(int a = 0)" << endl;
	}

protected:
	int _a;
};


// B 继承 A类

class B : public A
{

public:
	B(int a1 = 0)
		:_a1(a1)
		,_A(a1)
	{
		cout << "B(int a1 = 0)" << endl;
	}

private:
	//这里会走初始化列表 , 初始化的顺序是声明的顺序
	//但是 基类是先被初始化的
	int _a1;
	A _A;
};

int main()
{

	B b;

	return 0;
}
#endif



/////////// 切片的使用

#if 0
// 基类
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "Person(int a = 0)" << endl;
	}

protected:
	int _a;
};


// B 继承 A类

class B : public A
{

public:
	B(int a1 = 0)
		:_a1(a1)
		, _A(a1)
	{
		cout << "B(int a1 = 0)" << endl;
	}

private:
	//这里会走初始化列表 , 初始化的顺序是声明的顺序
	//但是 基类是先被初始化的
	int _a1;
	A _A;
};


int main()
{
	// 派生类的对象可以赋值给基类的指针和引用,对象

	B b;

	//派生类的对象(b) 赋值给基类的指针
	A* pa = &b;

	//派生类的对象(b) 赋值给基类的引用
	A& aa = b;
	
	//派生类的对象(b) 赋值给基类的对象 -- 依靠拷贝构造
	A a;
	a = b;

	//基类对象不能赋值给派生类 , 会报错
	//b = a; err

	return 0;
}
#endif


/////////// 继承中的隐藏规则

//// 同名成员构成隐藏


#if 0
// 基类
class A
{
public:
	A(int a = 0)
		:_a(a)
	{
		cout << "Person(int a = 0)" << endl;
	}

protected:
	int _a;
};


// B 继承 A类

class B : public A
{

public:
	B(int a1 = 0)
		:_a1(a1)
	{
		cout << "B(int a1 = 0)" << endl;
	}

	void Print()
	{
		cout << _a1 << endl;
		cout << A::_a << endl;
		cout << _a << endl; // B 中的成员
	}

private:
	
	int _a1;
	int _a;
};




int main()
{
	B b;
	b.Print();

	return 0;
}

#endif 


//////////////// 隐藏部分重要面试题
#if 0
class A
{
	public :
	void func()
	{
		cout << "func()" << endl;
	}
};

class B : public A
{
	public :
	void func(int i)
	{
		cout << "func(int i)" << i << endl;
	}
};


int main()
{

	B b;
	b.func(10);
	//b.func();// 同名函数被隐藏了 , 所以报错

	return 0;
}
#endif 


///////////////////// 派生类的默认成员函数


// 默认成员函数有 :  1. 默认构造函数 2.拷贝构造 3. 赋值重载 4. 析构函数


//在派生类中可以把基类看做一个整体对待

#if 0
//基类
class A
{
public:

	//基类中有默认构造函数
	//A(int aa = 0)
	//	:_a(aa)
	//{
	//	cout << "A(int aa = 0)" << endl;
	//}

	//基类中没有默认构造函数 , 派生类中要显示调用


	A(int aa)
		:_a(aa)
	{
		cout << "A(int aa = 0)" << endl;
	}
protected:
	int _a;

};


//派生类中默认成员函数 

// 1. 默认构造函数 -- 有以下行为
// a . 我们不写编译器会自动生成一个 
// b . 要求必须调用基类的默认构造函数完成对基类的成员的初始化
// c . 对内置类型不确定 , 对自定义类型会调用它的默认构造
// d . 把基类看做一个整体 ,调用它的默认构造 ,若没有就必须在派生类中显示调用它的构造

//派生类 B
class B : public A
{
public:

	//基类中没有默认构造 ,派生类中就要在其构造函数中显示调用基类的构造函数

	B(int aa =  0, int bb = 1)
		:A(aa) // 这里建议写到开头 ,因为先会初始化基类
		,_b(bb)
	{
		cout << "B(int aa = 0, int bb = 1)" << endl;
	}

private:
	int _b;
	string _st = "张三";
};
int main()
{
	B b;

	return 0;
}
#endif

#if 0
class Person
{
public:

	//构造函数
	Person()
	{
		cout << "Person()" << endl;
	}

	//拷贝构造
	Person(const Person& person)
		:_name(person._name)
	{
		cout << "Person(const Person& person)" << endl;
	}

	//赋值重载
	Person& operator=(const Person& person)
	{


		if (this != &person)
		{
			cout << "Person& operator=(const Person& person)" << endl;
			_name = person._name;

		}

		return *this;
	}


	//析构函数
	~Person()
	{
		cout << "~Person()" << endl;
	}

protected:
	string _name = "张三"; // 姓名
};


class Student : public Person
{
public:

	// Student 构造函数要显示调用 Person 构造
	Student()
		:Person()
	{
		cout << "Student()" << endl;
	}

	// Student 拷贝构造函数要显示调用 Person 的拷贝构造
	Student(const Student& stu)
		:Person(stu) // 这里是切片操作 , 派生类对象可以赋值给基类,这里走了一个类型转换
		,_num(stu._num)
	{
		cout << "Student(const Student& stu)" << endl;
	}

	// Student 赋值重载函数要显示调用 Person 的赋值重载函数
	Student& operator=(const Student& stu)
	{
		if (this != &stu)
		{
			//基类要显示调用 ,因为同名构成隐藏
			cout << "Student& operator=(const Student& stu)" << endl;
			Person::operator=(stu);
			_num = stu._num;
		}

		return *this;
	}
	
	//析构不需要显示调用
	~Student()
	{
		cout << "~Student()" << endl;
	}
	
private:
	int _num = 231090; // 学号
};

int main()
{
	//构造
	Student st;
	//拷贝构造
	Student st1 = st;
	//赋值重载
	Student st2;

	st2 = st1;


	return 0;
}
#endif

///////////////// 总结 :

// 总之 , 派生类默认成员函数这里只需记住: 

// 一般不用我们写拷贝构造 ,赋值重载 , 析构函数
// 对于派生类默认成员函数
// 1. 内置类型 - > 不确定
// 2. 自定义类型 - > 调用它的相关函数 , 没有就报错
// 3. 基类 - > 看做一个整体
//    构造函数 , 拷贝构造函数 , 赋值重载都必须调用基类的这些函数 , 对于默认构造 ,基类有不用管 , 基类没有要在派生类的构造中显示调用基类的构造
//    析构函数不需要显示调用基类的析构函数


///////////////////////////////////////////////////// 实现不能被继承的类


// 方法1 . 基类中的构造函数私有 

#if 0
class A
{
private:

	A(int aa)
		:_a(aa)
	{
		cout << "A(int aa = 0)" << endl;
	}
private:
	int _a;

};

//派生类 B
class B : public A
{
public:


	B(int aa = 0, int bb = 1)
		:A(aa) 
		, _b(bb)
	{
		cout << "B(int aa = 0, int bb = 1)" << endl;
	}

private:
	int _b;
	string _st = "张三";
};
int main()
{
	B b;

	return 0;
}

#endif


//方法2 --- final
//class A final
//{
//public:
//
//	A(int aa)
//		:_a(aa)
//	{
//		cout << "A(int aa = 0)" << endl;
//	}
//private:
//	int _a;
//
//};
//
////派生类 B
//class B : public A
//{
//public:
//
//
//	B(int aa = 0, int bb = 1)
//		:A(aa)
//		, _b(bb)
//	{
//		cout << "B(int aa = 0, int bb = 1)" << endl;
//	}
//
//private:
//	int _b;
//	string _st = "张三";
//};
//int main()
//{
//	B b;
//
//	return 0;
//}


/////////////////////////// 友元不能继承
#if 0

//这里要有一个前置声明 , 因为 Student从上往下找找不到
class Student;

class Person
{
public:
	friend void Display(const Person& p, const Student& s);
protected:
	string _name;
};

class Student : public Person
{

public:

	// 没有就会报错: error C2248: “Student::_num”: 无法访问 protected 成员(在“Student”类中声明)

	//friend void Display(const Person& p, const Student& s);

protected:
	int _num;
};

void Display(const Person& p, const Student& s)
{
	
	cout << p._name << endl;  //  Display 为 Person 的友元
	cout << s._num << endl;
}


int main()
{

	return 0;
}
#endif 


//////////////// 

//class A
//{
//
//public:
//
//	A()
//	{
//		cout << _a << _b << endl;
//	}
//
//	int _a = 1;
//	static int _b;
//};
//
////静态成员初始化要这样
//int A::_b = 2;
//
//
//class B : public A
//{
//
//public:
//	int _a;
//};
//
//int main()
//{
//	A a;
//	B b;
//
//	//同名成员被继承 ,但是隐藏了基类的
//	cout << &a._a << endl;
//	cout << &b._a << endl;
//
//	// _b 地址一样证明 , 静态成员在继承体系中只有一个
//	cout << &a._b << endl;
//	cout << &b._b << endl;
//
//	return 0;
//}


//////////////////////////////// 解决菱形继承用 virtual

//class Person
//{
//	public :
//	string _name; // 姓名
//
//};
//// 使虚继承Person类
//class Student : virtual public Person
//{
//	protected :
//	int _num; //学号
//};
//// 使⽤虚继承Person类
//class Teacher : virtual public Person
//{
//	protected :
//	int _id; // 职⼯编号
//};
//// 教授助理
//class Assistant : public Student, public Teacher
//{
//	protected :
//	string _majorCourse; // 主修课程
//};
//int main()
//{
//	// 使⽤虚继承，可以解决数据冗余和二义性
//	Assistant a;
//	a._name = "peter";
//	return 0;
//}



class Base1 { public: int _b1; };
class Base2 { public: int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };


int main()
{
	Derive d;
	Base1* p1 = &d;
	Base2* p2 = &d;
	Derive* p3 = &d;
	return 0;
}

//组合与继承区分 
// is - a -- 继承
// has - a -- 组合

//////////////////////////////// 完 ................. 